# !/usr/bin/env python3
# -*- coding: utf-8 -*-

from typing import List, Dict, Union
import xml.etree.ElementTree as EleTree
from tsn_builder_struct.index_tbl_structure import IndexTbl, IndexTblEachNode, IndexEntry_union, IndexEntry
from lib.tsn_builder_lib import host_to_net
from tsn_builder_linker.reg_addr_parser import RegAddr


def link_index_tbl(node: dict,
                 index_tbl: IndexTbl,
                 reg_addr: RegAddr) -> List[Dict[str, Union[str, List[str]]]]:
    # 找到该节点对应的转发表
    node_id = node['src_node']
    tbl_each_node = []
    for tbl in index_tbl.tbl_set:
        if tbl.node_id == node_id:
            tbl_each_node = tbl.tbl_each_node
            #[print(entry) for entry in tbl_each_node]
            break

    if not tbl_each_node:
        return []

    # 处理该节点的转发表的每一条表项
    # 硬件将flow_id作为索引查表，因此flow_id与转发表寄存器基地址
    # 之间存在映射关系
    dic = []  # 返回值
    for entry in tbl_each_node:
        flow_id = entry.flow_id
        flow_type = entry.flow_type
        # 如果flow_id不为空，说明
        # 该流在该节点有转发表表项
        if flow_id is not None:
            index_entry = entry.index_entry
            value1 = index_entry.byte.entry1
            value1_str = host_to_net(value1)

            # 计算该转发表的地址
            addr = reg_addr.index_tbl['addr']
            width = reg_addr.index_tbl['width']
            index = flow_type << 14
            index = index | flow_id
            addr = addr + index * width
            addr_str = host_to_net(addr)
            addr_value = {
                'addr': addr_str,
                'value': [value1_str]
            }
            dic.append(addr_value)
    return dic


def _get_index_tbl(index_tbl_xml):
    index_entry_set = []
    root = EleTree.parse(index_tbl_xml)
    node_ele_set = root.findall('node')
    for node_ele in node_ele_set:
        node_entry = {}
        node_id = node_ele.findtext('node_id')
        node_entry.update({'node_id': int(node_id)})
        entry_ele_set = node_ele.findall('entry')
        node_entry.update({'entry_set': []})
        for entry_ele in entry_ele_set:
            valid = 1 # entry_ele.findtext('valid')
            reserved = 0 # entry_ele.findtext('reserved')
            flow_id = entry_ele.findtext('flow_id')
            flow_type = 0 # entry_ele.findtext('flow_type')
            entry = {
                'valid': int(valid),
                'reserved': int(reserved),
                'flow_id': int(flow_id),
                'flow_type': int(flow_type)
            }
            node_entry['entry_set'].append(entry)
        index_entry_set.append(node_entry)
    return index_entry_set


def _init_index_tbl_obj(index_entry_set):
    index_tbl = IndexTbl()
    for tbl_each_node in index_entry_set:
        node_id = tbl_each_node['node_id']
        entry_set = tbl_each_node['entry_set']
        index_tbl_each_node = IndexTblEachNode(node_id)
        for entry in entry_set:
            index_entry_union = IndexEntry_union()
            valid = entry['valid']
            index_entry_union.bit.valid = valid
            reserved = entry['reserved']
            index_entry_union.bit.reserved = reserved
            flow_id = entry['flow_id']
            index_entry_union.bit.etc_index = flow_id
            flow_type = entry['flow_type']
            index_entry = IndexEntry(flow_id,
                                     flow_type,
                                     index_entry_union)
            index_tbl_each_node.append_entry(index_entry)
        index_tbl.append_tbl(index_tbl_each_node)
    return index_tbl


def read_index_tbl(cb_tbl_xml):
    # 从index_tbl_xml中读取index_entry_set
    index_entry_set = _get_index_tbl(cb_tbl_xml)
    [print(entry) for entry in index_entry_set]

    # 初始化FwdTbl类的对象
    index_tbl = _init_index_tbl_obj(index_entry_set)

    return index_tbl


def main():
    cb_tbl_xml = '../output/tbl/cb_tbl.xml'
    index_tbl = read_index_tbl(cb_tbl_xml)


if __name__ == '__main__':
    main()
